﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PatternVisitor
{
    class Program
    {
        static void Main(string[] args)
        {

            EggRobot eggRobot = new EggRobot();

            eggRobot.calc();


            IVisitor update = new UpdateVisitor();
            eggRobot.Accept(update);
            eggRobot.calc();

            Console.ReadKey();
             
        }
    }

    class EggRobot
    {
        //CPU CPU;
        //HardDisk HardDisk;
        List<Hardware> hardwares = new List<Hardware>();

        public EggRobot()
        {
            //CPU = new CPU("1+1=1");
            //HardDisk = new HardDisk("remenber : 1+1=1");

            hardwares.Add(new CPU("1+1=1"));
            hardwares.Add(new HardDisk("remenber : 1+1=1"));
        }

        public void calc()
        {
            //CPU.Run();
            //HardDisk.Run();

            foreach (Hardware hardware in hardwares)
            {
                hardware.Run();
            }
        }


        public void Accept(IVisitor visitor)
        {
            //CPU.Accept(visitor);
            //HardDisk.Accept(visitor);

            foreach (Hardware hardware in hardwares)
            {
                hardware.Accept(visitor);
            } 
        }

          
    }

    interface IVisitor
    {
        void VisitCPU(CPU cpu);
        void VisitHardDisk(HardDisk hardDisk);
    }

    class UpdateVisitor : IVisitor
    {
        public void VisitCPU(CPU cpu)
        {
           cpu.AddCommand("1+1=2"); ;
        }

        public void VisitHardDisk(HardDisk hardDisk)
        {
            hardDisk.AddCommand("remember : 1+1=2\n"); ;
        }
    }


    abstract class Hardware
    {
        protected string command;
        public Hardware(string  _command)
        {
            command = _command;
        }

        public void Run()
        {
            Console.WriteLine("RUN"+ command);
        }
        public void AddCommand(string moreCmd)
        {
             command += moreCmd;
        }
        public string ShowCommand()
        {
            return command;
        }

        public abstract void Accept(IVisitor visitor); 
    
    }


    class CPU : Hardware
    {

        public CPU(string command):base(command)
        {
            base.command = command;
        }
        public override void Accept(IVisitor visitor)
        {
            visitor.VisitCPU(this);
        }
    }
    class HardDisk : Hardware
    {

        public HardDisk(string command) : base(command)
        {
            base.command = command;
        }
        public override void Accept(IVisitor visitor)
        {
            visitor.VisitHardDisk(this);
        }
    }

}
